package com.bee.bootstrap;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.toolkit.IdWorker;
import com.bee.bootstrap.constant.RedisCacheKey;
import com.bee.bootstrap.plugs.redis.RedisCacheManager;
import com.bee.bootstrap.resource.entity.Resource;
import com.bee.bootstrap.resource.service.IResourceService;
import com.bee.bootstrap.plugs.swagger.ApiTags;
import com.bee.common.core.enums.ResourceTypeEnum;
import com.bee.common.core.enums.StatusEnum;
import com.bee.common.tools.web.PermissionConvert;
import io.swagger.models.Swagger;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.service.Documentation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * 启动后根据swagger解析的api去数据库初始化系统资源列表,每次启动都会去更新数据库
 */
@Component
@Order(1)
public class ResourceApplicationRunner implements  ApplicationRunner {

    @Autowired
    private DocumentationCache documentationCache;

    @Autowired
    private ServiceModelToSwagger2Mapper mapper;

    @Autowired
    private JsonSerializer jsonSerializer;

    @Autowired
    private IResourceService resourceServiceImpl;

    @Autowired
    private RedisCacheManager redisCacheManager;

    @Override
    @Transactional
    public void run(ApplicationArguments applicationArguments) throws Exception {
        Documentation documentation = documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
        if (documentation == null) {
            return;
        }
        Swagger swagger = mapper.mapDocumentation(documentation);
        Json json=jsonSerializer.toJson(swagger);
        if(json!=null){
            JSONObject jsonObject=JSONObject.fromObject(json.value());
            JSONArray tagsJson=jsonObject.getJSONArray("tags");
            JSONObject pathJson=jsonObject.getJSONObject("paths");
            List<ApiTags> tags= (ArrayList<ApiTags>) JSONArray.toCollection(tagsJson,ApiTags.class);
            //所有父级菜单
            List<Resource> menus=new ArrayList<Resource>();
            List<Resource> removeResources=new ArrayList<Resource>();
            List<String> url=new ArrayList<String>();
            List<String> permissions=new ArrayList<>();
            tags.forEach(tag->{
                Resource resource=new Resource();
                resource.setCode(tag.getName());
                resource.setCreateTime(new Date());
                resource.setName(tag.getDescription());
                resource.setPermission(tag.getName()+":*");
                resource.setCode(tag.getName());
                resource.setPriority(1);
                resource.setStatus(StatusEnum.NORMAL.toString());
                resource.setUrl("/"+tag.getName());
                resource.setType(ResourceTypeEnum.MENU.toString());
                menus.add(resource);
                permissions.add(tag.getName()+":*");
            });
            //更新数据
            List<Resource> persistences=resourceServiceImpl.selectList(new EntityWrapper<Resource>().in("permission",permissions));
            if(persistences!=null&&persistences.size()>0){
                for(Resource persistence:persistences){
                    for(Resource resource:menus){
                        if(resource.getPermission().equals(persistence.getPermission())){
                            removeResources.add(resource);
                        }
                    }
                }
                menus.removeAll(removeResources);
            }
            //保存菜单资源
            if(menus.size()>0){
                resourceServiceImpl.insertBatch(menus);
            }
            //子资源
            List<Resource> childResources=new ArrayList<Resource>();
            Iterator iterator = pathJson.keys();
            while(iterator.hasNext()){
                String path = (String) iterator.next();
                JSONObject pathJsonJSONObject = pathJson.getJSONObject(path);
                Iterator pathIterator = pathJsonJSONObject.keys();
                while(pathIterator.hasNext()){
                    String method = (String) pathIterator.next();  //方法类型：POST,PUT,DELETE,GET
                    JSONObject methodBody = pathJsonJSONObject.getJSONObject(method);
                    String tag=methodBody.getJSONArray("tags").get(0).toString();
                    Resource parentResource=resourceServiceImpl.selectOne(new EntityWrapper<Resource>()
                            .eq("url","/"+tag).eq("type",ResourceTypeEnum.MENU.toString()).isNull("parent_id"));
                    String description= methodBody.get("description")==null?"":methodBody.get("description").toString();
                    String summary=methodBody.get("summary")==null?"":methodBody.get("summary").toString();
                    Resource resource=new Resource();
                    resource.setId(IdWorker.getId());
                    resource.setType(ResourceTypeEnum.BUTTON.toString());
                    resource.setUrl(path);
                    resource.setStatus(StatusEnum.NORMAL.toString());
                    resource.setCode(tag);
                    resource.setName(summary);
                    resource.setCreateTime(new Date());
                    if(parentResource!=null){
                        resource.setFullParentIds(parentResource.getId().toString());
                        resource.setParentId(parentResource.getId());
                    }
                    resource.setPermission(resource.getCode()+":"+PermissionConvert.permission(method));
                    childResources.add(resource);
                    url.add(path);
                }
            }
            removeResources.clear();
            //旧数据不更新
            persistences=resourceServiceImpl.selectList(new EntityWrapper<Resource>().in("url",url).isNotNull("parent_id"));
            List<Resource> insertList=new ArrayList<Resource>();
            for(Resource persistence:persistences){
                for(Resource childResource:childResources){
                    if(persistence.getUrl().equals(childResource.getUrl())&&persistence.getPermission().equals(childResource.getPermission())){
                        removeResources.add(childResource);
                    }
                }
            }
            childResources.removeAll(removeResources);
            //插入的子资源
            if(childResources.size()>0){
                resourceServiceImpl.insertOrUpdateBatch(childResources);
            }
        }
        List<Resource> resources=resourceServiceImpl.selectList(new EntityWrapper<Resource>().eq("status",StatusEnum.NORMAL.toString()));
        if(resources!=null&&!resources.isEmpty()){
            redisCacheManager.getCache(RedisCacheKey.RESOURCE_KEY).put(RedisCacheKey.RESOURCE_KEY,resources);
        }
    }
}
